<?php

declare(strict_types=1);

namespace app\common\service\sys;

use app\common\traits\ServiceTrait;
use app\common\dao\sys\UserDao;
use app\common\dao\sys\UserRoleDao;
use app\common\util\JwtUtil;
use app\common\exception\MyException;
use think\facade\Cache;

/**
 * 系统用户 - 业务
 * @author:kaige
 * @date:2022-06-13
 * @copyright ©2022 泉州市盛筑信息科技有限公司 版权所有
 */
class UserService
{
  protected $dao = null;

  public function __construct()
  {
    $this->dao = new UserDao();
  }
  use ServiceTrait;

  /**
   * 用户身份验证
   */
  public function checkAdmin($userToken)
  {
    if (empty($userToken) || strlen($userToken) < 10) {
      throw new MyException(['code' => 2101]);
    }
    $payload = JwtUtil::decode($userToken);
    if (empty($payload) || empty($payload['uid']) || empty($payload['last_time'])) {
      throw new MyException(['code' => 2101]);
    }
    //用户登录有效期
    $userLastTime = config('kaige.user_last_time');
    if ($payload['last_time'] < time() - $userLastTime) {
      throw new MyException(['code' => 2102]);
    }
    // 实时用户数据
    $user = $this->dao->getInfoById($payload['uid']);
    //用户是否存在
    if (empty($user)) {
      throw new MyException(['code' => 2104]);
    } else {
      $user = $user->toArray();
    }
    //是否多设备登录 -- 如果要开启，需解决把之前其它设备登录的踢掉。
    // if (!empty($user['last_time']) && $user['last_time'] != $payload['last_time']) {
    //   throw new MyException(['code' => 2103]);
    // }
    //用户状态
    if ($user['status'] != 1) {
      throw new MyException(['code' => 2106]);
    }
    return array('user' => $user);
  }

  /**
   * 重写 搜索条件
   * @param $post
   * @return mixed
   */
  public function _list_where($post)
  {
    $where = [];
    $order = ['id' => 'desc'];
    $field = ['*'];
    if (isset($post['search_date']) && !empty($post['search_date'])) {
      $date_string = $post['search_date'];
      $date_array = explode('到', urldecode($date_string));
      $stime = strtotime($date_array[0] . '00:00:00');
      $etime = strtotime($date_array[1] . '23:59:59');
      $where[] = ['entry_time', 'between', [$stime, $etime]];
    }
    if (isset($post['search_code']) && $post['search_code'] != "") {
      $where[] = ['code', '=', $post['search_code']];
    }
    if (isset($post['keywords']) && !empty($post['keywords'])) {
      $where[] = ['un|real_name|phone', 'like', '%' . $post['keywords'] . '%'];
    }
    if (isset($post['search_status']) && !empty($post['search_status'])) {
      $where[] = ['status', '=', $post['search_status']];
    }
    if (isset($post['search_sex']) && $post['search_sex'] != "") {
      $where[] = ['sex', '=', $post['search_sex']];
    }
    if (isset($post['search_on_duty']) && $post['search_on_duty'] != "") {
      $where[] = ['on_duty', '=', $post['search_on_duty']];
    }
    if (isset($post['company_id']) && !empty($post['company_id'])) {
      $where[] = ['company_id', '=', $post['company_id']];
    }
    if (isset($post['dept_id']) && !empty($post['dept_id'])) {
      $where[] = ['dept_id', '=', $post['dept_id']];
    }
    //排序
    if (isset($post['sortfield']) && $post['sortfield'] != "") {
      if (isset($post['sortord']) && $post['sortord'] != "") {
        $order[$post['sortfield']] = $post['sortord'];
      }
    }
    if (isset($post['automatch']) && $post['automatch'] == 1) {
      $field = "id,real_name as name,real_name,phone,dept_id,dept_id_name,ranking_id,ranking_id_name,super_id,super_name,company_id,entry_time,avatar";
      $where[] = ['status', '=', 1];
    }
    $result['where'] = $where;
    $result['field'] = $field;
    $result['order'] = $order;
    return $result;
  }

  /**
   * 重写 根据查询结果格式化数据
   * @param $list
   * @return mixed
   */
  public function _list_format($list)
  {
    $rs = new RoleService();
    $roleList = $rs->getListAll();
    foreach ($list as $k => $v) {
      if (isset($v['avatar'])) {
        $list[$k]['avatar'] = _img($v['avatar']);
      }
      if (isset($v['last_time'])) {
        $list[$k]['last_time'] = time2str($v['last_time']);
      }
      if (isset($v['entry_time'])) {
        $list[$k]['entry_time'] = time2str($v['entry_time'], 2);
      }
      if (isset($v['dimission_time'])) {
        $list[$k]['dimission_time'] = time2str($v['dimission_time'], 2);
      }
      if (isset($v['last_push_time'])) {
        $list[$k]['last_push_time'] = time2str($v['last_push_time']);
      }
      if (isset($v['pwd'])) {
        unset($v['pwd']);
      }
      if (isset($v['sz_salt'])) {
        unset($v['sz_salt']);
      }
      if (isset($v['glcompany'])) {
        unset($v['glcompany']);
      }
    }
    return $list;
  }

  /**
   * 添加、编辑数据
   * @param $data
   * @return array|mixed
   */
  public function saveUserForm($data)
  {
    $this->formatData($data);
    //判断是新增还是修改
    if (isset($data['id'])) {
      $userInfo = $this->dao->getInfoById($data['id']);
      if (!$userInfo) {
        return _err('查无记录');
      }
      if (isset($data['pwd']) && !empty($data['pwd'])) {
        if (strlen($data['pwd']) <= 5 || strlen($data['pwd']) > 32) {
          return _err('无效密码');
        } else {
          if (empty($userInfo['sz_salt'])) {
            $sz_salt = md5(create_guid());
            $data['sz_salt'] = $sz_salt;
          } else {
            $sz_salt = $userInfo['sz_salt'];
          }
          $data['pwd'] = encrypt_pass($data['pwd'], $sz_salt, $userInfo['create_time']);
        }
      } else {
        unset($data['pwd']);
      }
      unset($data['un']); //不允许修改用户名
      if (isset($data['avatar']) && !empty($data['avatar'])) {
        _use_file($userInfo['avatar'], -1); //旧图扣掉次数
        _use_file($data['avatar'], 1); //新图加次数
      }
      //更新数据库
      $this->dao->update($data['id'], $data);
    } else {
      if (!isset($data['un']) && isset($data['real_name'])) {
        $data['un'] = $data['real_name'];
      }
      //判断用户名是否重复
      if ($this->dao->userExist($data['un'])) {
        return _err('用户名已经存在');
      }
      $data['create_time'] = time();
      if (isset($data['avatar']) && !empty($data['avatar'])) {
        _use_file($data['avatar'], 1); //新图加次数
      }
      if (isset($data['pwd']) && !empty($data['pwd'])) {
        if (strlen($data['pwd']) <= 5 || strlen($data['pwd']) > 32) {
          return _err('无效密码');
        } else {
          $data['sz_salt'] = md5(create_guid());
          $data['pwd'] = encrypt_pass($data['pwd'], $data['sz_salt'],  $data['create_time']);
        }
      } else {
        unset($data['pwd']);
      }
      //插入数据库
      $outobj = $this->dao->add($data);
      $data['id'] = $outobj->id;
    }
    if (isset($data['role_id']) && !empty($data['role_id'])) {
      //设置角色
      $userRoleDao = new UserRoleDao();
      $userRoleDao->clearUserId($data['id']);
      $data1 = [];
      foreach ($data['role_id'] as $v) {
        $row['user_id'] = $data['id'];
        $row['role_id']   = $v;
        $data1[]          = $row;
      }
      $userRoleDao->saveAllUserRole($data1);
    }
    return _ok('操作成功', $data['id']);
  }

  /**
   * 格式化添加、编辑时的保存数据
   * @param $data
   * @return void
   */
  protected function formatData(&$data)
  {
    $data['status']         = checkon('status', $data);
    $data['type']           = checkon('type', $data);
    $data['is_balance']     = checkon('is_balance', $data);
    $data['is_kq']          = checkon('is_kq', $data);
    $data['is_card']        = checkon('is_card', $data);
    $data['is_app_push']    = checkon('is_app_push', $data);
    $data['last_time']      = str2time('last_time', $data);
    $data['entry_time']     = str2time('entry_time', $data);
    $data['dimission_time'] = str2time('dimission_time', $data);
  }

  /**
   * 系统用户登录
   * @param $data
   * @return array
   */
  public function login($data)
  {
    if (!isset($data['username']) || !isset($data['password'])) {
      return _err('请正确输入账户或密码！');
    }
    //验证输入
    $sysuservalidate = new \app\common\validate\sys\User();
    $revli = $sysuservalidate->check([
      'un' => $data['username'],
      'pwd' => $data['password'],
    ]);
    if (!$revli) {
      $this->lfnadd();
      return _err($sysuservalidate->getError());
    }

    //校验验证码
    if (cache('sys_login_fail_num')) {
      if (cache('sys_login_fail_num') >= config('kaige.sys_login_fail_num')) {
        $this->lfnadd();
        if (!isset($data['key']) || empty($data['key'])) {
          return _err(1004, 1004);
        }
        if (!isset($data['captcha']) || empty($data['captcha'])) {
          return _err(2109, 2109);
        }
        if (!captcha_check($data['key'], $data['captcha'])) {
          return _err(2110, 2110);
        };
      }
    }
    //找出 用户名或手机号或姓名 等于输入 账户
    $where = [];
    $where[] = ['un|phone|real_name', '=', $data['username']];
    $field1 = ['id,client_id,bn,un,pwd,ln,status,type,sex,avatar,sign,dept_id,dept_id_name,company_id,phone,last_time,last_ip,real_name,create_time,sz_salt'];
    $userInfo = $this->dao->getInfoByWhereObj($where, $field1);
    if (!$userInfo) {
      $this->lfnadd();
      return _err('没有找到此账号');
    }
    //判断账号状态
    if ($userInfo->status != 1) {
      $this->lfnadd();
      return _err('此账号已停用');
    }
    $nowpwd = encrypt_pass($data['password'], $userInfo->sz_salt, $userInfo->create_time);
    //判断密码
    $ispwd = $userInfo->pwd === $nowpwd;
    if ($ispwd) {
      $sdata = $userInfo->toArray();
      $time = time();
      $ip = _gip();
      //更新登录信息
      $upData = [
        'ln'        => $userInfo->ln + 1,
        'last_ip'   => $ip,
        'last_time' => $time,
        'online' => 1
      ];
      $this->dao->update($userInfo->id, $upData);
      unset($sdata['pwd']); //删除密码字段
      //登录事件
      event('UserLog', [$sdata, 'backend/login/index', $time, _gip(), '登录', '']);
      // 多端统一使用Jwt方式验证
      // 令牌生成
      $payload['uid']       = $userInfo->id;
      $payload['last_time'] = $time;
      $user_token           = JwtUtil::encode($payload);
      // 前端要的用户信息，必须是重新写数组，不能直接输出查询结果。
      $userinfo = [
        'uid'             => $userInfo->id,
        'client_id'       => $userInfo->client_id,
        'un'              => $userInfo->un,
        'ln'              => $userInfo->ln,
        'sex'             => $userInfo->sex,
        'avatar'          => _img($userInfo->avatar),
        'sign'            => $userInfo->sign,
        'dept_id'         => $userInfo->dept_id,
        'dept_id_name'    => $userInfo->dept_id_name,
        'ranking_id'      => $userInfo->ranking_id,
        'ranking_id_name' => $userInfo->ranking_id_name,
        'real_name'       => $userInfo->real_name,
        'company_id'      => $userInfo->company_id,
        'phone'           => $userInfo->phone,
        'theme'           => $userInfo->theme,
      ];
      $usbData = [
        'token' => $user_token,
        'userinfo' => $userinfo
      ];
      return _ok('用户登录系统成功', $usbData);
    } else {
      $this->lfnadd();
      return _err('密码错误，请重试');
    }
    return _err('登录失败');
  }

  // 登录验证失败次数记录
  private function lfnadd()
  {
    //写失败次数到缓存里
    $tmp = cache('sys_login_fail_num');
    if ($tmp) {
      cache('sys_login_fail_num', $tmp + 1, 300); //缓存5分钟
    } else {
      cache('sys_login_fail_num', 1, 300); //缓存5分钟
    }
  }

  /**
   * 退出登录
   */
  public static function toLogout($uid)
  {
    (new UserDao())->update($uid, ['online' => 2, 'last_time' => time()]);
    // 清除用户独有的节点缓存
    $key = config('kaige.cache_key') . $uid;
    Cache::delete($key); //清除节点缓存
    Cache::delete('sys_login_fail_num'); //清除登录验证失败次数 ‘本无树’
    // Cache::delete(config('kaige.sys_uid_loginkey') . '_' . $uid);
    return _ok('退出系统成功');
  }


  /**
   * 管理员修改密码
   * @param $uid
   * @param $oldPassword
   * @param $newPassword
   * @return array|string
   */
  public function chengePwd($uid, $oldPassword, $newPassword)
  {
    $result = [
      'status' => false,
      'data'   => '',
      'msg'    => ''
    ];
    $info = $this->dao->getInfoByWhereObj(['id' => $uid]);
    if (!$info) {
      return _err('查无此用户');
    }

    if ($info->pwd != encrypt_pass($oldPassword, $info->sz_salt, $info->create_time)) {
      return _err('原密码错误');
    }
    // 居然是修改，盐值也更新吧
    $sz_salt = md5(create_guid());
    $updata = [
      'pwd' => encrypt_pass($newPassword, $sz_salt, $info->create_time),
      'sz_salt' => $sz_salt
    ];
    $re = $this->dao->update($uid, $updata);
    if ($re) {
      return _ok(1021);
    } else {
      return _err(1022);
    }
  }


  /**
   * 根据用户ID获取公司ID
   */
  public function getCompanyIdByUserId($uid)
  {
    return $this->dao->getCompanyIdByUserId($uid);
  }

  /**
   * 查重
   */
  public function userExist($username)
  {
    return $this->dao->userExist($username);
  }

  /**
   * 获取员工列表
   * @return array
   */
  public function getEmployeeList()
  {
    return $this->dao->getEmployeeList();
  }

  /**
   * 获取员工列表 -- API 使用
   * @return array
   */
  public function getEmployeeListUseAPI()
  {
    $list = $this->dao->getEmployeeListUseAPI();
    if ($list) {
      foreach ($list as $k1 => $v1) {
        if (isset($v1['avatar'])) {
          $list[$k1]['avatar'] = _img($v1['avatar']);
        }
      }
    }
    return $list;
  }

  /**
   * 依ID获取用户姓名
   * @return string
   */
  public function getEmployeeName($id)
  {
    return $this->dao->getEmployeeName($id);
  }
  /**
   * 依ID获取用户信息
   * @return array
   */
  public function getEmployeeInfo($id)
  {
    return $this->dao->getEmployeeInfo($id);
  }

  /**
   * 取根据部门下所有人员
   */
  public function getDeptUserList($dept_id = 0)
  {
    return $this->dao->getDeptUserList($dept_id);
  }

  /**
   * 根据公司ID获取用户ID集
   */
  public function getUserIdByCompanyId($company_id = 0)
  {
    return $this->dao->getUserIdByCompanyId($company_id);
  }
  /**
   * 根据部门ID获取用户ID集
   */
  public function getUserIdByDeptId($dept_id = 0)
  {
    return $this->dao->getUserIdByDeptId($dept_id);
  }

  /**
   * 获取上级主管-所有
   */
  public function getUserSuperInfo($user_id = 0)
  {
    $data = [];
    $info = $this->dao->getInfoById($user_id, true, ['super_id', 'super_name', 'id', 'real_name']);
    if (!$info) {
      return $data;
    }
    $info = object_array($info);
    //判断是否还有父节点，如果有，就取父节点，如果没有，就返回了
    if ($info['super_id'] > 0) {
      $data = $this->getUserSuperInfo($info['super_id']); //返回空数组或者二维数组
    }
    array_push($data, $info);
    return $data;
  }
}
